package org.charmsoft.utils;

import org.apache.poi.ss.usermodel.*;
import org.charmsoft.dto.ClassPO;
import org.charmsoft.dto.ClassesInSheet;
import org.charmsoft.dto.Field;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ Author: Allen J L Chen
 * This Class is to
 * 26/3/2025
 **/
public class ExcelUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelUtils.class);

    private static final ReentrantLock lock = new ReentrantLock();

    public static void deleteEmptyRow(Sheet sheet) {
        int rowCount = sheet.getLastRowNum();
        for(int i = 0 ; i <= rowCount; i++) {
            Row row = sheet.getRow(i);
            if(row != null && isEmptyRow(row)){
                sheet.removeRow(row);
            }
        }
    }

    public static boolean isEmptyRow(Row row) {
        boolean isEmpty = true;
        for(Cell cell : row) {
            if(cell.getCellType() != CellType.BLANK && (!cell.getStringCellValue().trim().isEmpty() || cell.getCellType()!= CellType.STRING)) {
                isEmpty = false;
                break;
            }
        }

        return isEmpty;
    }

    public static ClassesInSheet getSheetClasses(Sheet sheet) {
        int rowCount = sheet.getPhysicalNumberOfRows();
        ClassesInSheet classesInSheet = new ClassesInSheet();
        Map<String, ClassPO> classPOMap = new ConcurrentHashMap<>();

        // Get pojo
        Row secondRow = sheet.getRow(1);
        Map<Integer, Cell> pojoNameCells = loopCellBySkipOneColumn(secondRow, 0);

        for(Cell cell : pojoNameCells.values()) {
            ClassPO classPO = new ClassPO();
            Cell pojoNameCell = cell;
            String pojoName = pojoNameCell.getStringCellValue();
            classPO.setName(pojoName);

            Map<Field, Field> fileds = new ConcurrentHashMap<>();
            for(int i = 3; i <= rowCount; i++) {
                Row row = sheet.getRow(i);
                if(row != null) {
                    LOGGER.info(String.valueOf(pojoNameCell.getColumnIndex()));
                    Field field = loopCellsInColumn(row, pojoNameCell.getColumnIndex());
                    fileds.put(field,field);
                }

            }

            classPO.setFields(fileds);
            classPOMap.put(pojoName,classPO);
        }

        classesInSheet.setClassPOMap(classPOMap);

        return classesInSheet;
    }

    /**
     * Loo cells in column to map field.
     * @param row
     * @param cellIndex
     * @return
     */

    public static Field loopCellsInColumn(Row row, int cellIndex) {
        Field field = new Field();

        Cell fieldNameCell = row.getCell(cellIndex);
        Cell fieldTypeCell = row.getCell(cellIndex+1);
        Cell sqlDataTypeCell = row.getCell(cellIndex + 2);
        String fieldName;
        String fieldType;
        String sqlDataType;
        if(fieldNameCell != null) {
            fieldName = fieldNameCell.getStringCellValue();
            field.setName(fieldName);
        }

        if(fieldTypeCell != null) {
            fieldType = fieldTypeCell.getStringCellValue();
            field.setFieldType(fieldType);
        }

        if(sqlDataTypeCell != null) {
            sqlDataType = sqlDataTypeCell.getStringCellValue();
            field.setSqlDataType(sqlDataType);
        }

        return field;
    }

    /**
     * Loop cell by skip one column.
     * @param row
     * @return
     */
    public static Map<Integer, Cell> loopCellBySkipOneColumn(Row row, int cellIndex) {

        Map<Integer, Cell> cellMap = new HashMap<>();
        for(int i = cellIndex; i <= row.getLastCellNum(); i+=4) {
            Cell  cell = row.getCell(i);
            if(cell != null) {
                lock.lock();
                cellMap.put(cell.getColumnIndex(), cell);
                lock.unlock();
            }
        }
        return cellMap;
    }

    /**
     * Update workbook.
     * @param workbook
     * @param path
     */
    public static void writeWorkbook(Workbook workbook, String path) {

        try (FileOutputStream outputStream = new FileOutputStream(path)) {
            workbook.write(outputStream);
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
        }
    }
}
